package common.model.Entity;

import common.util.DateUtils;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

/**
 * 基础实体类，所有实体类的父类。
 * <p>
 * 提供了通用的字段与方法，包括：
 * <ul>
 *   <li>ID 主键</li>
 *   <li>创建时间 {@code createdAt}</li>
 *   <li>更新时间 {@code updatedAt}</li>
 *   <li>逻辑删除标记 {@code isDeleted}</li>
 * </ul>
 * 该类同时提供了一些便捷方法，用于维护时间戳和逻辑删除状态。
 * </p>
 */
@Getter
@Setter
public abstract class BaseEntity {

    /**
     * 实体的唯一标识
     */
    private Long id;

    /**
     * 创建时间
     */
    private LocalDateTime createdAt;

    /**
     * 更新时间
     */
    private LocalDateTime updatedAt;

    /**
     * 逻辑删除标记：
     * <ul>
     *   <li>0 - 未删除</li>
     *   <li>1 - 已删除</li>
     * </ul>
     */
    private Integer isDeleted = 0;

    /**
     * 默认构造函数，初始化 {@code createdAt} 和 {@code updatedAt} 为当前时间。
     */
    protected BaseEntity() {
        this.createdAt = DateUtils.now();
        this.updatedAt = this.createdAt;
    }

    /**
     * 带 ID 的构造函数，初始化基础字段。
     *
     * @param id 实体 ID
     */
    protected BaseEntity(Long id) {
        this();
        this.id = id;
    }

    /**
     * 设置主键 ID，并更新更新时间。
     *
     * @param id 实体 ID
     */
    public void setId(Long id) {
        this.id = id;
        this.updateTimestamps();
    }

    /**
     * 设置逻辑删除状态，并更新更新时间。
     *
     * @param isDeleted 逻辑删除状态（0=未删除，1=已删除）
     */
    public void setIsDeleted(Integer isDeleted) {
        this.isDeleted = isDeleted;
        this.updateTimestamps();
    }

    /**
     * 判断当前实体是否已被逻辑删除。
     *
     * @return {@code true} 如果已删除；否则返回 {@code false}
     */
    public boolean isDeleted() {
        return isDeleted != null && isDeleted == 1;
    }

    /**
     * 将实体标记为已删除（{@code isDeleted = 1}）。
     */
    public void markAsDeleted() {
        this.isDeleted = 1;
        this.updateTimestamps();
    }

    /**
     * 将实体标记为未删除（{@code isDeleted = 0}）。
     */
    public void markAsUndeleted() {
        this.isDeleted = 0;
        this.updateTimestamps();
    }

    /**
     * 更新时间戳，将 {@code updatedAt} 设置为当前时间。
     * 如果 {@code createdAt} 为空，也会同步设置为当前时间。
     */
    public void updateTimestamps() {
        this.updatedAt = DateUtils.now();
        if (this.createdAt == null) {
            this.createdAt = this.updatedAt;
        }
    }

    /**
     * 获取格式化后的创建时间字符串。
     *
     * @return 格式化后的创建时间
     */
    public String getCreatedAtFormatted() {
        return DateUtils.format(createdAt);
    }

    /**
     * 获取格式化后的更新时间字符串。
     *
     * @return 格式化后的更新时间
     */
    public String getUpdatedAtFormatted() {
        return DateUtils.format(updatedAt);
    }

    /**
     * 判断是否为新建对象（ID 为空或为 0）。
     *
     * @return {@code true} 如果对象未持久化；否则返回 {@code false}
     */
    public boolean isNew() {
        return id == null || id == 0L;
    }

    /**
     * 返回实体对象的字符串表示形式。
     *
     * @return 字符串形式，包含 id、创建时间、更新时间、逻辑删除状态
     */
    @Override
    public String toString() {
        return this.getClass().getSimpleName() + "{" +
                "id=" + id +
                ", createdAt=" + getCreatedAtFormatted() +
                ", updatedAt=" + getUpdatedAtFormatted() +
                ", isDeleted=" + isDeleted +
                '}';
    }

    /**
     * 判断两个实体是否相等（基于 ID 判断）。
     *
     * @param o 对象
     * @return 如果 ID 相同则返回 {@code true}
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        BaseEntity that = (BaseEntity) o;
        return id != null && id.equals(that.id);
    }

    /**
     * 返回哈希值（基于 ID）。
     *
     * @return 哈希值
     */
    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}
